package com.green.service.common.log;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import com.green.common.OperateTypeEnum;
import com.green.model.Entity;
import com.green.model.annotation.OperateLogEntity;
import com.green.model.annotation.OperateLogMethod;
import com.green.model.manage.OperateLog;
import com.green.service.common.ServiceContext;

@Aspect
@Component
@Lazy(value = false)
public class OperateLogAop {

	@Autowired
	private GeneralOperateLogger generalOperateLogger;

	private static final Logger LOGGER = Logger.getLogger(OperateLogAop.class);

	@Pointcut("execution(* com.green.dao..*.insert*(..))")
	public void insertOperateLog() {
	}

	@Pointcut("execution(* com.green.dao..*.update*(..))")
	public void updateOperateLog() {
	}

	@Pointcut("execution(* com.green.dao..*.delete*(..))")
	public void delOperateLog() {
	}

	/**
	 * 新增操作
	 * 
	 * @param pjp
	 * @return
	 * @throws Throwable
	 */
	@SuppressWarnings("rawtypes")
	@Around("insertOperateLog()")
	public Object insertProcess(ProceedingJoinPoint pjp) throws Throwable {
		Object obj = pjp.proceed(pjp.getArgs());
		Entity entity = isStandard(pjp);
		if (entity != null) {
			recordLog(pjp, entity, null);
		}
		return obj;
	}

	/**
	 * 修改操作
	 * 
	 * @param pjp
	 * @return
	 * @throws Throwable
	 */
	@SuppressWarnings("rawtypes")
	@Around("updateOperateLog()")
	public Object updateProcess(ProceedingJoinPoint pjp) throws Throwable {
		 //查询出更改前对象值 
		Entity entity= isStandard(pjp);
		Object historyObj=null;
		if(entity!=null){
			historyObj= queryHistoryObject(entity, pjp.getTarget());
		 }
		Object obj = pjp.proceed(pjp.getArgs());		
		if(entity!=null&&historyObj!=null){
			recordLog(pjp,entity,historyObj);
		 }
		return obj;
	}

	/**
	 * 删除操作
	 * 
	 * @param jp
	 * @return
	 * @throws Throwable
	 */
	@SuppressWarnings("rawtypes")
	@Before("delOperateLog()")
	public void delProcess(JoinPoint jp) throws Throwable {
		Entity entity = isStandard(jp);
		if(entity != null){
			Object historyObj = queryHistoryObject(entity, jp.getTarget());
			if (historyObj != null) {
				recordLog(jp, entity, historyObj);
			}
		}
	}

	/**
	 * 获取方法注解
	 * 
	 * @param pjp
	 * @return
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 */
	private OperateLogMethod getOperateLogMethod(JoinPoint pjp) throws SecurityException, NoSuchMethodException {
		/***
		 * 判断是否存在日志注解
		 */
		MethodSignature joinPointObject = (MethodSignature) pjp.getSignature();
		Method method = joinPointObject.getMethod();
		try {
			Method methodSun = pjp.getTarget().getClass().getDeclaredMethod(method.getName(), method.getParameterTypes());
			boolean flag = methodSun.isAnnotationPresent(OperateLogMethod.class);
			if (!flag) {
				return null;
			}
			return methodSun.getAnnotation(OperateLogMethod.class);
		} catch (Exception e) {
			// 找不到方法，可能在父类中
			return null;
		}

	}

	/**
	 * 判断是否标准
	 * 
	 * @param pjp
	 * @return
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private Entity isStandard(JoinPoint pjp) throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException {
		Entity entity = null;
		OperateLogMethod operateLogMethod = getOperateLogMethod(pjp);
		if (operateLogMethod == null) {
			return null;
		}
		/* 获取参数 */
		Object[] args = pjp.getArgs();
		if (args != null && args.length > 0) {
			/** 判断是否实体对象 */

			for (Object object : args) {
				if (object instanceof Entity) {
					entity = (Entity) object;
				} else if (object instanceof String) {
					entity = (Entity) operateLogMethod.delClassName().newInstance();
					entity.setId(object.toString());
				}
			}
			if (entity == null) {
				return null;
			}
			/*
			 * 获取类注解 判断是有类注解
			 */
			if (!entity.getClass().isAnnotationPresent(OperateLogEntity.class)) {
				return null;
			}
		}
		return entity;
	}

	/**
	 * 获取历史对象
	 * 
	 * @return
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 */
	@SuppressWarnings("rawtypes")
	private Object queryHistoryObject(Entity entity, Object object) throws Exception {
		OperateLogEntity operateLogEntity = entity.getClass().getAnnotation(OperateLogEntity.class);
		String methodName = operateLogEntity.method();
		Method method = object.getClass().getDeclaredMethod(methodName, String.class);

		String id = (String) entity.getId();
		if (StringUtils.isNotBlank(id)) {
			return method.invoke(object, id);
		}

		return null;
	}

	/**
	 * 记录日志
	 * 
	 * @param pjp
	 * @return
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 */
	@SuppressWarnings("rawtypes")
	private void recordLog(JoinPoint pjp, Entity entity, Object historyObj) throws SecurityException, NoSuchMethodException {

		OperateLogMethod operateLogMethod = getOperateLogMethod(pjp);
		OperateLogEntity operateLogEntity = entity.getClass().getAnnotation(OperateLogEntity.class);

		/* 操作属性是否记录日志 */
		Field[] fields = entity.getClass().getDeclaredFields();
		try {
			String content = StringUtils.EMPTY;
			if (OperateTypeEnum.ADD.name().equals(operateLogMethod.value())) {
				content = generalOperateLogger.getAddOperateContent(fields, entity);
			} else if (OperateTypeEnum.UPDATE.name().equals(operateLogMethod.value())) {
				content = generalOperateLogger.getUpdateOperateContent(fields, entity, historyObj);
			} else if (OperateTypeEnum.DEL.name().equals(operateLogMethod.value())) {
				content = generalOperateLogger.getDelOperateContent(fields, historyObj);
			}
			content = StringUtils.replace(content, "null", StringUtils.EMPTY);
			if (StringUtils.isBlank(content)) {
				return;
			}
			if(ServiceContext.getLoginPerson() != null){
				OperateLog operateLog = new OperateLog();
				operateLog.setUUID();
				operateLog.setOperateLogType(operateLogEntity.type());
				operateLog.setCreateBy(ServiceContext.getLoginPerson());
				operateLog.setContent(content);
				operateLog.setPersonName(ServiceContext.getLoginPerson().getName());
				operateLog.setIp(ServiceContext.getRequestIP());
				generalOperateLogger.doLog(operateLog);
			}

		} catch (Exception e) {
			LOGGER.error(e.getMessage(), e);
		}

	}

	/**
	 * 获取对象中方法返回值
	 * 
	 * @param methodName
	 * @param obj
	 * @return
	 */
	@SuppressWarnings("unused")
	private String getMethodValue(String methodName, Object obj) {
		String id = "";
		try {
			id = (String) obj.getClass().getMethod(methodName).invoke(obj, null);
		} catch (Exception e) {
			LOGGER.error(e);

		}
		return id;
	}
}
